import datetime
import os
import re

import openpyxl
from bs4 import BeautifulSoup
from config import OUTPUT_DIRS_DEFAULT, DEFINE_FUNCTIONS, DEFINE_TYPEDEFS, DEFINE_STRUCTS, DEFINE_MACROS
from get_api_class import get_api_in_homepage
from get_game_api import get_game_in_homepage, get_target_from_web
from spiders import spider


def __get_api_functions(flag, response):
    data = []
    name = str
    # web = "https://developer.android.google.cn/ndk/reference"
    resp = response.text
    soup = BeautifulSoup(resp, "html.parser")
    include_list = soup.find_all('code', dir='ltr')
    try:
        include_str = include_list[0].get_text()
        if not include_str.startswith('#include'):
            include_file = 'None'
        else:
            pattern = re.compile(r'#include <(.*)>', re.M | re.S)
            include_file = pattern.match(include_str).group(1)
    except:
        include_file = 'None'
    function_table = soup.find('table', class_='methods responsive')
    if function_table:
        tr_list = function_table.find_all('tr')
        for tr in tr_list:
            td_list = tr.find_all('td')
            try:
                code = td_list[0].find('code')
                full_name = code.get_text()
                # print(full_name)
                if '(' in full_name:
                    name_list = full_name.split('(')
                    name = name_list[0]
                    params = '(' + name_list[1]
                    if params == '()':
                        params = 'None'
                else:
                    name = full_name
                    params = 'None'
                description = td_list[1].get_text().strip()
                types = DEFINE_FUNCTIONS
                classify = (flag, name, params, description, types, include_file)
                data.append(classify)
            except:
                print('functions error: ')
                continue
    structs_table_list = soup.find_all('table', class_='constants responsive')
    if structs_table_list:
        for structs_table in structs_table_list:
            title_list = structs_table.find_all('h3')
            for title in title_list:
                print('title :' + title.text)
                if title.text == 'Structs':
                    print('yes')
                    tr_list = structs_table.find_all('tr')
                    # print(tr_list)
                    for tr in tr_list:
                        td_list = tr.find_all('td')
                        try:
                            a = td_list[0].find('a')
                            full_name = a.text
                            if '(' in full_name:
                                name_list = full_name.split('(')
                                name = name_list[0]
                                params = '(' + name_list[1]
                                if params == '()':
                                    params = 'None'
                            else:
                                params = 'None'
                                name = full_name
                            description = td_list[1].get_text().strip()
                            types = DEFINE_STRUCTS
                            classify = (flag, name, params, description, types, include_file)
                            data.append(classify)
                        except:
                            print('Structs error: ')
                            continue
    typedefs_table_list = soup.find_all('table', class_='properties responsive')
    if typedefs_table_list:
        for typedefs_table in typedefs_table_list:
            title_list = typedefs_table.find_all('h3')
            for title in title_list:
                tr_list = typedefs_table.find_all('tr')
                # print(tr_list)
                for tr in tr_list:
                    td_list = tr.find_all('td')
                    try:
                        code = td_list[0].find('code')
                        full_name = code.get_text()
                        if '(' in full_name:
                            name_list = full_name.split('(')
                            name = name_list[0].replace(')', '')
                            params = '(' + name_list[1]
                            if params == '()':
                                params = 'None'
                        else:
                            params = 'None'
                            name = full_name
                        description = td_list[1].get_text().strip()
                        types = title.text
                        classify = (flag, name, params, description, types, include_file)
                        data.append(classify)
                    except:
                        print('Typedefs error: ')
                        continue
    macros_table_list = soup.find_all('table', class_='responsive')
    if macros_table_list:
        for macros_table in macros_table_list:
            title_list = macros_table.find_all('h3')
            for title in title_list:
                if title.text == 'Macros':
                    tr_list = macros_table.find_all('tr')
                    # print(tr_list)
                    for tr in tr_list:
                        td_list = tr.find_all('td')
                        try:
                            code = td_list[0].find('a')
                            # print(code)
                            full_name = code.get_text()
                            if '(' in full_name:
                                name_list = full_name.split('(')
                                name = name_list[0]
                                params = '(' + name_list[1]
                                if params == '()':
                                    params = 'None'
                            else:
                                name = full_name
                                params = 'None'
                            description = td_list[1].get_text().strip()
                            types = DEFINE_MACROS
                            classify = (flag, name, params, description, types, include_file)
                            data.append(classify)
                        except:
                            print('Macros error ')
                            continue
    return data

def __get_api_classes(flag, response):
    data = []
    resp = response.text
    soup = BeautifulSoup(resp, "html.parser")
    title_name = soup.find('h1')
    class_name = title_name.get_text()
    include_list = soup.find_all('code', dir='ltr')
    try:
        include_str = include_list[0].get_text()
        if not include_str.startswith('#include'):
            include_file = 'None'
        else:
            pattern = re.compile(r'#include <(.*)>', re.M | re.S)
            include_file = pattern.match(include_str).group(1)
    except:
        include_file = 'None'
    try:
        constructor_table = soup.find('table', class_='constructors responsive')
    except:
        constructor_table = None
    if constructor_table:
        tr_list = constructor_table.find_all('tr')
        for tr in tr_list:
            try:
                td_list = tr.find_all('td')
                code = td_list[0].find('code')
                full_name = code.get_text()
                if len(td_list) > 1:
                    description = td_list[1].get_text().strip()
                else:
                    description = 'None'
                if '(' in full_name:
                    name_list = full_name.split('(')
                    name = name_list[0]
                    params = '(' + name_list[1]
                    if params == '()':
                        params = 'None'
                else:
                    name = full_name
                    params = 'None'
                types = "Constructors and Destructors"
                classify = (class_name, name, params, description, types, include_file)
                data.append(classify)
            except:
                continue
    try:
        types_table_list = soup.find_all('table', class_='constants responsive')
    except:
        types_table_list = None
    if types_table_list:
        for types_table in types_table_list:
            title_list = types_table.find_all('h3')
            for title in title_list:
                print('title :' + title.text)
                if title.text == 'Public types':
                    print('yes')
                    tr_list = types_table.find_all('tr')
                    # print(tr_list)
                    for tr in tr_list:
                        td_list = tr.find_all('td')
                        try:
                            code = td_list[0].find('code')
                            full_name = code.get_text()
                            if len(td_list) > 1:
                                description = td_list[1].get_text().strip()
                            else:
                                description = 'None'
                            if '{' in full_name:
                                name_list = full_name.split('{')
                                name = name_list[0]
                                # print("{{{" + name_list[1].replace('  ', '').replace(' ', ''))
                                params = '{' + name_list[1].replace('  ', '').replace(' ', '')
                                if params == '{}':
                                    params = 'None'
                            else:
                                params = 'None'
                                name = full_name
                            types = "Public types"
                            classify = (class_name, name, params, description, types, include_file)
                            data.append(classify)
                        except:
                            continue
    try:
        function_table_list = soup.find_all('table', class_='methods responsive')
    except:
        function_table_list = None
    if function_table_list:
        for function_table in function_table_list:
            title_list = function_table.find_all('h3')
            for title in title_list:
                print('title :' + title.text)
                if title.text == 'Public functions' or 'Public static functions':
                    print('yes')
                    tr_list = function_table.find_all('tr')
                    # print(tr_list)
                    for tr in tr_list:
                        td_list = tr.find_all('td')
                        try:
                            code = td_list[0].find('code')
                            full_name = code.get_text()
                            if len(td_list) > 1:
                                description = td_list[1].get_text().strip()
                            else:
                                description = 'None'
                            if '(' in full_name:
                                name_list = full_name.split('(')
                                name = name_list[0]
                                params = '(' + name_list[1].strip()
                                if params == '()':
                                    params = 'None'
                            else:
                                params = 'None'
                                name = full_name
                            types = title.text
                            classify = (class_name, name, params, description, types, include_file)
                            data.append(classify)
                        except:
                            continue
    try:
        attributes_table_list = soup.find_all('table', class_='properties responsive')
    except:
        attributes_table_list = None
    if attributes_table_list:
        for attributes_table in attributes_table_list:
            title_list = attributes_table.find_all('h3')
            for title in title_list:
                print('title :' + title.text)
                if title.text == 'Public attributes':
                    print('yes')
                    tr_list = attributes_table.find_all('tr')
                    # print(tr_list)
                    for tr in tr_list:
                        td_list = tr.find_all('td')
                        try:
                            code = td_list[0].find('code')
                            full_name = code.get_text()
                            if len(td_list) > 1:
                                description = td_list[1].get_text().strip()
                            else:
                                description = 'None'
                            if '(' in full_name:
                                name_list = full_name.split('(')
                                name = name_list[0]
                                params = '(' + name_list[1].strip()
                                if params == '()':
                                    params = 'None'
                            else:
                                params = 'None'
                                name = full_name
                            types = title.text
                            classify = (class_name, name, params, description, types, include_file)
                            data.append(classify)
                        except:
                            continue
    return data


def __get_android_api_in_class(classify_list):
    tasks_modules = list()
    tasks_classes = list()
    print(classify_list)
    for classify, url, types in classify_list:
        flag = classify
        task = (url, flag)
        if types == "modules":
            tasks_modules.append(task)
        elif types == "classes":
            tasks_classes.append(task)
    result_modules = spider(20, tasks_modules)
    result_classes = spider(20, tasks_classes)
    api_list = list()
    # print(result)
    for flag, response in result_modules:
        if response.status_code == 200:
            api_list += __get_api_functions(flag, response)
        else:
            print("ERR:Failed to connect html")
    for flag, response in result_classes:
        if response.status_code == 200:
            api_list += __get_api_classes(flag, response)
        else:
            print("ERR:Failed to connect html")
    return api_list

def get_android_api_all(classify_dict, save_file=None):
    time_now = datetime.datetime.now()
    date_time = "%s-%s-%s" % (time_now.year, time_now.month, time_now.day)
    if not save_file:
        if not (os.path.exists(OUTPUT_DIRS_DEFAULT)):
            os.mkdir(OUTPUT_DIRS_DEFAULT)
        work_dir = os.path.join(OUTPUT_DIRS_DEFAULT, date_time)
        if not (os.path.exists(work_dir)):
            os.mkdir(work_dir)
        save_file = os.path.join(work_dir, "android_api.xlsx")
    wb = openpyxl.Workbook()
    wb.remove(wb.active)
    for sdk_name, classify_list in classify_dict.items():
        api_list = __get_android_api_in_class(classify_list)
        # print(api_list)
        sheet = wb.create_sheet(sdk_name)
        sheet.cell(1, 1, "symbol")
        sheet.cell(1, 2, "type")
        sheet.cell(1, 3, "header")
        sheet.cell(1, 4, "modules/class")
        sheet.cell(1, 5, "status")
        sheet.cell(1, 6, "symbol_on_openharmony")
        sheet.cell(1, 7, "remarks")
        row = 2
        for modules, name, params, description, types, include in api_list:
            sheet.cell(row, 1, name)
            sheet.cell(row, 2, types)
            sheet.cell(row, 3, include)
            sheet.cell(row, 4, modules)
            sheet.cell(row, 5, 'missing')
            sheet.cell(row, 6, '')
            sheet.cell(row, 6, '')
            row += 1
    wb.save(save_file)
    return

if __name__ == "__main__":
    url_list = get_target_from_web('https://developer.android.google.cn/games/agdk/libraries-overview')
    dict1 = get_api_in_homepage()
    dict2 = get_game_in_homepage(url_list)
    dict1.update(dict2)
    print(dict1)
    get_android_api_all(dict1)
    # __get_android_api_in_class(classify_List)
